package com.polaris.live.im.manager

import android.content.Context
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.constant.CommonConst.ErrorCode.SENDGIFT
import com.polaris.live.common.mvvm.activity.BaseVmActivity
import com.polaris.live.common.network.AppException
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.im.db.entity.MessageEntity
import com.polaris.live.im.sfs.MESSAGE_STATUS_ERROR
import com.polaris.live.im.sfs.MESSAGE_STATUS_SENDING
import com.polaris.live.im.sfs.MESSAGE_STATUS_SUCCESS
import com.polaris.live.im.sfs.MESSAGE_STATUS_TIMEOUT
import com.polaris.live.im.sfs.bean.chat.SingleMessage
import com.polaris.live.im.sfs.bean.chat.ext.SingleMessageParameterBean
import com.polaris.live.im.sfs.bean.chat.response.SingleMessageReceipt
import com.polaris.live.im.sfs.core.SmartFoxManager
import com.polaris.live.im.sfs.core.SmartFoxQueueManager
import com.polaris.live.im.sfs.core.bean.resolveResponse
import com.polaris.live.im.utils.toSelfMessageEntity
import com.polaris.live.im.utils.toSelfSessionEntity
import com.polaris.live.im.utils.toSelfSingleMessage
import com.polaris.live.manager.AppConfigManager
import com.polaris.live.popup.GlobalPopupManager
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 消息的统一管理器
 *
 * @author Created by lucas on 2023/10/18 18:01
 * @since 1.0.0
 */
object ImManager {

    fun startImService() {
        AppConfigManager.getConfigPre()?.imConfig?.also {
            SmartFoxManager.setConfig(it)
            SmartFoxManager.connect()
        }
    }

    /**
     * 异步发送消息
     */
    fun sendMessageWithAsync(
        context: Context,
        command: String,
        singleMessage: SingleMessage,
        parameter: SingleMessageParameterBean? = null,
        isOnlySave: Boolean = false,
        onTransform: TransformMessageListener? = null,
        onCompleted: ((Throwable?) -> Unit)? = null,
    ) {
        SmartFoxManager.messageScope.launch {
            sendMessage(context, command, singleMessage, parameter, isOnlySave, onTransform, onCompleted)
        }
    }

    /**
     * 发送消息，自行控制消息内容及类型
     *
     * 如果发送不是[isOnlySave]，则自己直接构造[MESSAGE_STATUS_SUCCESS]的消息
     */
    suspend fun sendMessage(
        context: Context,
        command: String,
        singleMessage: SingleMessage,
        parameter: SingleMessageParameterBean? = null,
        isOnlySave: Boolean = false,
        onTransform: TransformMessageListener? = null,
        onCompleted: ((Throwable?) -> Unit)? = null,
    ) {
        val saveSession = singleMessage.toSelfSessionEntity(command)
        val messageEntity =
            singleMessage.toSelfMessageEntity(command, parameter?.let { JsonUtils.toJson(it) })

        //通知自己发送消息
        ImMessageManager.onDispatchSendMessage(messageEntity)

        try {
            //发送消息先更新数据库
            ImSessionManager.saveSession(saveSession, true)
            ImMessageManager.insertMessage(messageEntity)

            //如果需要真实发送则，则调用发送
            if (!isOnlySave) {
                val finalMessageEntity = if (onTransform != null) {
                    onTransform.onTransform(messageEntity).also {
                        //如果不等于说明需要数据有修改，需要重新保存一次
                        if (it != messageEntity) {
                            ImMessageManager.updateMessage(it)
                        }
                    }
                } else {
                    messageEntity
                }

                val finalSingleMessage = finalMessageEntity.toSelfSingleMessage()
                invokeSendMessage(command, finalSingleMessage, finalMessageEntity)
            }

            withContext(SmartFoxManager.noticeDispatcher) {
                onCompleted?.invoke(null)
            }
        } catch (t: Throwable) {
            invokeSendError(context, t, messageEntity)

            withContext(SmartFoxManager.noticeDispatcher) {
                onCompleted?.invoke(t)
            }
        }
    }

    /**
     * 消息重试
     */
    fun retrySendMessageWithIO(context: Context, messageEntity: MessageEntity, l: TransformMessageListener? = null) {
        SmartFoxManager.messageScope.launch {
            retrySendMessage(context, messageEntity, l)
        }
    }

    /**
     * 消息重试
     */
    suspend fun retrySendMessage(context: Context, messageEntity: MessageEntity, l: TransformMessageListener?) {
        try {
            val finalMessageEntity = if (l != null) {
                val entity = messageEntity.copy(state = MESSAGE_STATUS_SENDING)
                ImMessageManager.updateMessageAndDispatch(entity)

                l.onTransform(entity)
            } else {
                messageEntity
            }

            val newMessageEntity = finalMessageEntity.copy(
                state = MESSAGE_STATUS_SENDING
            )

            ImMessageManager.updateMessageAndDispatch(newMessageEntity)

            val singleMessage = finalMessageEntity.toSelfSingleMessage()
            invokeSendMessage(messageEntity.command, singleMessage, finalMessageEntity)
        } catch (t: Throwable) {
            invokeSendError(context, t, messageEntity)
        }
    }

    private suspend fun invokeSendMessage(
        command: String,
        singleMessage: SingleMessage,
        messageEntity: MessageEntity,
    ) {
        val resp = SmartFoxQueueManager.sendChatMessage(command, singleMessage)
        val receipt = resp.receipt.resolveResponse<SingleMessageReceipt>()

        val finalParameter = if (messageEntity.parameter == null) {
            receipt?.parameter
        } else {
            mergeParameter(receipt, messageEntity.parameter)
        }

        val state = if (receipt?.errorMessage != null) {
            MESSAGE_STATUS_ERROR
        } else {
            MESSAGE_STATUS_SUCCESS
        }

        val successMessageEntity = messageEntity.copy(
            //发送成功需要更新时间
            timestamp = CacheUtil.getServerTime(),
            state = state,
            seqId = receipt?.seqId,
            parameter = finalParameter,
            respErrorMessage = receipt?.errorMessage,
            retryExpiredTime = receipt?.retryExpiredTime,
            hotLevel = receipt?.hotLevel
        )
        ImMessageManager.updateMessageAndDispatch(successMessageEntity)
    }

    private suspend fun invokeSendError(context: Context, t: Throwable, messageEntity: MessageEntity) {
        if (t is AppException) {
            //送礼余额不足弹窗
            val giftErrorStatus = if (t.errCode == SENDGIFT) {
                withContext(SmartFoxManager.noticeDispatcher) {
                    ToastGravity.showGravity(t.message)

                    if (context is BaseVmActivity<*>) {
                        GlobalPopupManager.showRechargePopup(context, context.mViewModel, isNeedBottom = true)
                    }
                }
                MESSAGE_STATUS_TIMEOUT
            } else {
                withContext(SmartFoxManager.noticeDispatcher) {
                    if (t.message?.isNotEmpty() == true) {
                        ToastGravity.showGravity(t.message)
                    }
                }
                null
            }

            ImMessageManager.updateMessageStateErrorAndDispatch(
                messageEntity,
                messageEntity.timestamp,
                t.errCode,
                t.errorMsg,
                giftErrorStatus
            )
        } else {
            ImMessageManager.updateMessageStateAndDispatch(
                messageEntity,
                messageEntity.timestamp,
                MESSAGE_STATUS_TIMEOUT
            )

            withContext(SmartFoxManager.noticeDispatcher) {
                ToastGravity.showGravity(t.message)
            }
        }

        LogExt.logE("--net", t)
    }

    private fun mergeParameter(
        response: SingleMessageReceipt?,
        parameter: String,
    ): String {
        val jsonObject = if (response?.parameter != null) {
            val element = JsonParser.parseString(response.parameter)
            if (element.isJsonObject) {
                element.asJsonObject
            } else {
                JsonObject()
            }
        } else {
            JsonObject()
        }

        JsonParser.parseString(parameter).asJsonObject.also {
            it.entrySet().forEach { entry ->
                jsonObject.add(entry.key, entry.value)
            }
        }

        return jsonObject.toString()
    }
}

fun interface TransformMessageListener {

    suspend fun onTransform(messageEntity: MessageEntity): MessageEntity

}